package org.chickenhook.restrictionbypass.helpers;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.lang.reflect.Field;

public class Reflection {


    /**
     * 检索给定对象的成员
     * @param obj 包含成员
     * @param field 成员名称
     * @param <T> 成员的类型
     * @return 成员
     * @throws NoSuchFieldException 何时找到字段
     * @throws IllegalAccessException 当字段不可访问时
     */
    public static @Nullable
    <T> T getReflective(@NonNull Object obj, @NonNull String field) throws NoSuchFieldException, IllegalAccessException {
        return getReflective(obj, obj.getClass(), field);
    }

    /**
     * 检索给定对象的成员
     * @param obj 包含成员（在静态字段中可以为null）
     * @param cls 超类型的类
     * @param field 成员名称
     * @param <T> 成员的类型
     * @return 成员
     * @throws NoSuchFieldException 何时找到字段
     * @throws IllegalAccessException 当字段不可访问时
     */
    public static @Nullable
    <T> T getReflective(@Nullable Object obj, @NonNull Class<?> cls, @NonNull String field) throws NoSuchFieldException, IllegalAccessException {
        Field f = cls.getDeclaredField(field);
        f.setAccessible(true);
        return (T) f.get(obj);
    }



    /**
     * 设置给定对象的成员
     * @param obj 包含成员
     * @param field 成员名称
     * @param value 要设置的值
     * @throws NoSuchFieldException何时找到字段
     * @throws IllegalAccessException 当字段不可访问时
     */
    public static @Nullable
    void setReflective(@NonNull Object obj, @NonNull String field, @Nullable Object value) throws NoSuchFieldException, IllegalAccessException {
        setReflective(obj, obj.getClass(), field, value);
    }

    /**
     * 设置给定对象的成员
     * @param obj 包含成员
     * @param cls obj的超类
     * @param field 成员名称
     * @param value 要设置的值
     * @throws NoSuchFieldException 何时找到字段
     * @throws IllegalAccessException 当字段不可访问时
     */
    public static @Nullable
    void setReflective(@Nullable Object obj, @NonNull Class<?> cls, @NonNull String field, @Nullable Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = cls.getDeclaredField(field);
        f.setAccessible(true);
        f.set(obj, value);
    }
}
